﻿using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using SageKing.AspNetCore.Swagger;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SageKing.Extensions;

public static class DependencyInjectionExtensions
{
    public static SwaggerOptions swaggerOptions = new SwaggerOptions();
    /// <summary>
    /// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
    /// </summary>
    /// <param name="services"></param>
    /// <exception cref="InvalidOperationException"></exception>
    public static void AddSageKingSwaggerGen(this IServiceCollection services, IConfigurationManager configuration = null)
    {
        if (configuration != null)
        {
            var section = configuration.GetSection(swaggerOptions.SectionName);
            if (section.Exists())
            {
                section.Bind(swaggerOptions);
            }
        }

        services.AddSingleton(swaggerOptions);

        #region AddSwaggerGen 

        if (!swaggerOptions.Enable)
        {
            Console.WriteLine("AddSageKingSwaggerGen: Swagger is disabled.");
            return;
        }

        services.AddEndpointsApiExplorer();

        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc(swaggerOptions.Version, new OpenApiInfo
            {
                Version = swaggerOptions.Version,
                Title = swaggerOptions.Title,
                Description = swaggerOptions.Description
            });

            c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
            {
                In = ParameterLocation.Header,
                Name = "Authorization",
                Description = "Example: \"Bearer {token}\"",
                Type = SecuritySchemeType.ApiKey,
                Scheme = "bearer", // 这里通常小写，但客户端发送时是 "Bearer"
                BearerFormat = "JWT"
            });
            // 2. 添加安全要求（这很关键，它确保授权信息被添加到请求中）
            c.AddSecurityRequirement(new OpenApiSecurityRequirement
            {
                {
                    new OpenApiSecurityScheme
                    {
                        Reference = new OpenApiReference
                        {
                            Type = ReferenceType.SecurityScheme,
                            Id = "Bearer" // 必须与 AddSecurityDefinition 中的名字一致
                        }
                    },
                    new string[] {}
                }
            });
            c.DocInclusionPredicate((name, api) => api.HttpMethod != null);
            //c.DocInclusionPredicate((name, api) =>
            //{
            //    return true;
            //});
            c.TagActionsBy(api =>
            {
                if (api.GroupName != null)
                {
                    return [api.GroupName];
                }

                if (api.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
                {
                    return [controllerActionDescriptor.ControllerName];
                }

                return [api.RelativePath];

                //throw new InvalidOperationException("Unable to determine tag for endpoint.");
            });
            c.ResolveConflictingActions(apiDescriptions =>
            {
                return apiDescriptions.First();
            });
        });

        #endregion 
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="app"></param>
    public static WebApplication UseSageKingSwaggerGen(this WebApplication app, IConfigurationManager configuration = null)
    {
        if (!swaggerOptions.Enable)
        {
            Console.WriteLine("UseSageKingSwaggerGen:Swagger is disabled.");
            return app;
        }

        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint(swaggerOptions.EndpointUrl, swaggerOptions.ApiName);
        });
        return app;
    }
}
